package com.xuecheng.content.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.commons.constants.CourseConstants;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.CourseBaseDto;
import com.xuecheng.commons.model.dto.CourseDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.CourseBaseVo;
import com.xuecheng.commons.model.vo.PageResponseResult;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.utils.AuthInfoHolder;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.config.MinioTemplate;
import com.xuecheng.content.domain.CourseBase;
import com.xuecheng.content.domain.Teachplan;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.CoursePubService;
import com.xuecheng.content.service.TeachplanService;
import com.xuecheng.web.exception.BusinessException;
import io.minio.Result;
import io.minio.errors.ErrorResponseException;
import io.minio.errors.InsufficientDataException;
import io.minio.errors.InvalidBucketNameException;
import io.minio.messages.Item;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import javax.management.openmbean.InvalidKeyException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itheima
 * @since 2022-12-03
 */
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private MinioTemplate minioTemplate;

    @Autowired
    private TeachplanService teachplanService;

    @Autowired
    private CoursePubService coursePubService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private AsyncCoursePubService asyncCourseService;

    // 分页+条件查询
    /*@Override
    public ResponseResult<CourseBaseVo> findByPage(PageRequest pageRequest, CourseDto dto) {
        //1.构建分页
        Page<CourseBase> page = new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize());
        //2.构建条件
        LambdaQueryWrapper<CourseBase> qw = new LambdaQueryWrapper<>();
        //2-1 课程名称
        qw.like(StrUtil.isNotEmpty(dto.getCourseName()), CourseBase::getName, dto.getCourseName());
        //2-2 课程状态
        qw.eq(StrUtil.isNotEmpty(dto.getAuditStatus()), CourseBase::getAuditStatus, dto.getAuditStatus());
        //2-3 课程类型
        qw.eq(StrUtil.isNotEmpty(dto.getTeachmode()), CourseBase::getTeachmode, dto.getTeachmode());
        //3.分页查询
        page = this.page(page, qw);
        //4.转vo
        List<CourseBase> courseBaseList = page.getRecords();
        List<CourseBaseVo> voList = new ArrayList<>();
        for (CourseBase courseBase : courseBaseList) {
            CourseBaseVo vo = BeanHelper.copyProperties(courseBase, CourseBaseVo.class);
            voList.add(vo);
        }
        //5.返回结果
        return PageResponseResult.okResult(page.getTotal(), voList);
    }*/

    // 分页+条件查询
    @Override
    public ResponseResult<CourseBaseVo> findByPage(PageRequest pageRequest, CourseDto dto) {
        // 1.构建分页
        Page<CourseBase> page = new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize());
        // 2.构建条件
        page = this.lambdaQuery()
                .like(StrUtil.isNotEmpty(dto.getCourseName()), CourseBase::getName, dto.getCourseName()) // 课程名称
                .eq(StrUtil.isNotEmpty(dto.getAuditStatus()), CourseBase::getAuditStatus, dto.getAuditStatus()) // 课程状态
                .eq(StrUtil.isNotEmpty(dto.getTeachmode()), CourseBase::getTeachmode, dto.getTeachmode()) // 课程类型
                // 多租户的数据隔离，设置根据机构id查询。
                // .eq(CourseBase::getCompanyId, AuthInfoHolder.getCompanyId())
                .page(page); // 3.分页查询
        // 4.转vo
        List<CourseBaseVo> voList = BeanHelper.copyWithCollection(page.getRecords(), CourseBaseVo.class);
        // 5.返回结果
        return PageResponseResult.okResult(page.getTotal(), voList);
    }



    // 课程新增
    @Override
    public ResponseResult<Map> saveCourseBase(CourseBaseDto dto) {
        // 1.校验前端参数(新增：id和价格不能校验)
        if (!StrUtil.isAllNotEmpty(dto.getName(), dto.getTags(), dto.getMt(), dto.getSt(), dto.getGrade())) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        // 2.dto转entity
        CourseBase courseBase = BeanHelper.copyProperties(dto, CourseBase.class);
        // 3.补全课程信息
        courseBase.setAuditStatus(CourseConstants.AUDIT_UNPAST_STATUS);// 未提交课程状态
        courseBase.setPlanNum(0); // 课程小节数量
        courseBase.setCreateDate(new Date());// 课程新增时间
        // 4.保存数据库
        boolean isSuccess = this.save(courseBase);
        if (isSuccess == false) {
            throw new BusinessException(ErrorCode.ADDEERROR);// 添加失败异常
        }
        // 5.初始化一级大纲（预留）
        Teachplan teachplan = new Teachplan();
        teachplan.setPname(courseBase.getName()); // 一级大纲名称（课程信息名称）
        teachplan.setParentid(0L); // 一级大纲父节点id为0
        teachplan.setGrade(1); // 一级
        teachplan.setDescription(courseBase.getDescription()); // 课程介绍
        teachplan.setCourseId(courseBase.getId());// 课程id
        teachplan.setCreateDate(new Date());// 创建时间
        teachplanService.save(teachplan);

        // 6.返回课程id
        Map map = new HashMap();
        map.put("courseBaseId", courseBase.getId());
        return ResponseResult.okResult(map);
    }


    // 课程修改
    @Override
    public ResponseResult<Map> updateCourseBase(CourseBaseDto dto) {
        // 1.校验前端参数（修改：价格不能校验）
        if (!StrUtil.isAllNotEmpty(dto.getName(), dto.getTags(), dto.getMt(), dto.getSt(), dto.getGrade())) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        if (ObjectUtil.isEmpty(dto.getId())) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        // 2.校验课程状态
        // 2-1查询数据库
        CourseBase oldCourseBase = this.getById(dto.getId());
        // 2-2 判断状态
        if (StrUtil.equals(oldCourseBase.getAuditStatus(), CourseConstants.AUDIT_PUBLISHED_STATUS)) {
            // 已发布(上架)课程不能修改
            throw new BusinessException(ErrorCode.MEDIABINDERROR);
        }
        // 3.dto转实体
        CourseBase newCourseBase = BeanHelper.copyProperties(dto, CourseBase.class);
        newCourseBase.setAuditStatus(CourseConstants.AUDIT_UNPAST_STATUS); // 设置课程状态为未提交
        // 4.更新数据库
        boolean isSuccess = this.updateById(newCourseBase);
        if (isSuccess == false) {
            throw new BusinessException(ErrorCode.UPDATEEERROR);
        }
        // 5.更新课程计划 （一级大纲）
        // 5-1 查询对应的一级大纲 select * from tb_teachplan where course_id = 47 and grade =1
        Teachplan oneTeachplan = teachplanService.lambdaQuery()
                .eq(Teachplan::getCourseId, newCourseBase.getId())
                .eq(Teachplan::getGrade, 1).one();
        // 5-2 修改名称和介绍
        oneTeachplan.setPname(newCourseBase.getName());
        oneTeachplan.setDescription(newCourseBase.getDescription());
        // 5-3 更新数据库
        teachplanService.updateById(oneTeachplan);
        // 6.返回课程id
        Map map = new HashMap();
        map.put("courseBaseId", oldCourseBase.getId());
        return ResponseResult.okResult(map);
    }

    // 课程删除
    @Override
    @Transactional // 添加事务 （必须）
    public ResponseResult deleteCourseBase(Long courseId) {
        // 1.校验课程状态
        // 1-1根据id查询课程
        CourseBase courseBase = this.getById(courseId);
        // 1-2判断课程是否发布
        if (StrUtil.equals(CourseConstants.AUDIT_PUBLISHED_STATUS, courseBase.getAuditStatus())) {
            throw new BusinessException(ErrorCode.DELETEERROR);
        }
        //删除minio
        minioTemplate.remove(courseBase.getPic());

        // 2.删除课程
        boolean isSuccess = this.removeById(courseId);
        if (isSuccess == false) {
            throw new BusinessException(ErrorCode.DELETEERROR);
        }

        // 判断 该课程下有一二三级不允许删除(计数方式)
        Long count = teachplanService.lambdaQuery()
                .eq(Teachplan::getCourseId, courseId).count();
        if (count > 1) {// 有二级或者三级
            throw new BusinessException(ErrorCode.DELETEERROR);
        }
        // 只有一级的话，直接删除
        // teachplanService.remove(teachplanService.lambdaQuery()
        //         .eq(Teachplan::getCourseId, courseId));
        LambdaQueryWrapper<Teachplan> qw = new LambdaQueryWrapper<>();
        qw.eq(Teachplan::getCourseId, courseId);
        teachplanService.remove(qw);

        // 3.返回删除成功 状态码：200
        return ResponseResult.okResult();
    }

    //课程下架
    @Override
    public ResponseResult offlineCourse(Long courseId) {
        //0.检测课程状态
        CourseBase courseBase = this.getById(courseId);
        String auditStatus = courseBase.getAuditStatus();
        //只有已发布的才可以下架
        if (!auditStatus.equals(CourseConstants.AUDIT_PUBLISHED_STATUS)) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        //1.修改状态
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CourseBase::getId, courseBase.getId());
        //这里设置的为下架状态202006，也可以设置为未提交状态
        updateWrapper.set(CourseBase::getAuditStatus, CourseConstants.AUDIT_UNLINE_STATUS);
        this.update(updateWrapper);
        //2.删除数据库 课程和发布ID相同
        coursePubService.removeById(courseId);
        //3.删除minio文件 这里封装到了异步service里面，本质就是一个minio的删除
        minioTemplate.deleteHtml(courseId);
        //4.MQ发送消息到search微服务
        rabbitTemplate.convertAndSend("content-exchange", "course.down",courseBase.getId().toString());
        return ResponseResult.okResult();
    }


}
